#ifndef 	__UPDATER_H__
#define 	__UPDATER_H__

#define 	F_COMPRESS	 1
#define		F_DECOMPRESS 2

#include "updater.types.h"

#define MAJOR	0
#define MINOR	1

/* definition for package header struct */

#define PACKET_MAGIC_SIZE	8
#define PACKET_DESCRIPTION_SIZE 1024
#define PACKET_NAME_SIZE 		32
#define PACKET_CNTSUM_SIZE	MD5LEN
#define PACKET_RESERVED_SIZE	1024
#define PACKET_PACKAGER_SIZE	256

#define PACKET_MINOR_TYPE	INT
#define PACKET_MAJOR_TYPE INT
#define PACKET_FLAGS_TYPE	LONG
#define PACKET_VERSION_TYPE INT

#define PACKET_MAGIC_WORD		"<13|31>>"

/* definition for file header struct */

#define FH_FILE_SIZE_TYPE	size_t
#define FH_CNTSUM_SIZE		MD5LEN
#define FH_MINOR_TYPE			INT
#define FH_MAJOR_TYPE			INT
#define FH_QUEUE_TYPE			INT
#define FH_DESCRIPTION_SIZE	512
#define FH_PATH_SIZE			1024
#define FH_COMPRESS_IN_TYPE	ULONG
#define FH_COMPRESS_OUT_TYPE	ULONG
#define FH_ENCRIPT_IN_TYPE	ULONG
#define FH_ENCRIPT_OUT_TYPE	ULONG
#define FH_DEPTH                64
#define FL_COMPRESSOR_SIZE		16
#define FL_ENCRIPTOR_SIZE		16
#define FL_MACRO_NAME_SIZE	32
#define ENV_NAME_SIZE			1024
#define GROUP_MAX_LEN 			256

#define MACSIZE		6
#define IPSIZE			4


#define TMP			"/tmp/"
#define TEST_MAGIC(c)       w_memcmp(c, PACKET_MAGIC_WORD, PACKET_MAGIC_SIZE)

#define SET_FLAG(a,b)       do{a |= b;}while(0)
#define UNSET_FLAG(a,b)     do{a &= ~b;} while(0)
#define CHECK_FLAG(a,b)		( ( a & b ) == b )

/* 	flags of file */
#define UPD_INSTALL_PATH	1 		/* This means: if no such path - create dirs. */
#define UPD_INSTALL_FORCE	(1<<1)	/* This means: install anyway even such file exists */
#define UPD_INSTALL_TARGET	(1<<2)	/* This means: update dedicated for concrete machine - encoded */
#define UPD_BACKUP			(1<<3)	/* This means: if file exists backup one */
#define UPD_RUN     	    (1<<4)	/* This means: Extract this file and run it. */
#define UPD_RUN_ONLY	    (1<<5)	/* This means: Extract this file, run it and delete ufter the run . */

#define UPD_HAS_PREINSTALL	(1<<6)	/* This means: it has script to run before install. */
#define UPD_HAS_POSTINSTALL	(1<<7)	/* This means: it has script to run after install. */
#define UPD_HAS_DEPS	    (1<<8)	/* This means: This package has dependencies in special file . */


#define UPD_INSTALL_PATH_NAME 	"UPD_INSTALL_PATH"
#define UPD_INSTALL_FORCE_NAME	"UPD_INSTALL_FORCE"
#define UPD_INSTALL_TARGET_NAME	"UPD_INSTALL_TARGET"
#define UPD_BACKUP_NAME 			"UPD_BACKUP"

#define DEFAULT_BUFF_SMALL      4056
#define DEFAULT_BUFF_BIG        8192

#define PREINSTALL_SCRIPT_NAME		"updater.preinstall"
#define POSTINSTALL_SCRIPT_NAME		"updater.postinstall"

struct packet_header 
{
  CHAR control_sum[PACKET_CNTSUM_SIZE];		    /* Control sum of whole package */
  CHAR magic[PACKET_MAGIC_SIZE];				/* A magic word */
  PACKET_MAJOR_TYPE major;						/* Package major */
  PACKET_MINOR_TYPE minor;						/* Package minor */
  PACKET_FLAGS_TYPE flags;						/* Package flags */
  PACKET_VERSION_TYPE version;					/* Version of packager */
  CHAR name[PACKET_NAME_SIZE];					/* Name of the package */
  CHAR description[PACKET_DESCRIPTION_SIZE];	/* Description of whole package */
  CHAR reserved[PACKET_RESERVED_SIZE];			/* Reserved for user */
};


struct file_header {
  FH_FILE_SIZE_TYPE size;			/* size of data section without the header */
  FH_QUEUE_TYPE		queue;			/* number in queue for install. Begin from 1. */
  STAT_T 		    *stat;			/* state of file 			*/
  INT 				major;			/* major - use for checking	*/
  INT 				minor;			/* minor - for checking		*/
  ULONG				flags;			/* misc flags				*/
  CHAR				compressor[16];	/* number of used compressor */
  CHAR				encriptor[16];		/* number of used encriptor	 */
  CHAR 				name[FH_PATH_SIZE];					/* name of file	(without path) */
  CHAR 				orig_path[FH_PATH_SIZE];					/* path to original file	*/
  CHAR 				target_path[FH_PATH_SIZE];					/* path where to install file	*/
  CHAR 				description[FH_DESCRIPTION_SIZE];	/* description of the file	*/
  FH_COMPRESS_IN_TYPE 	compress_in_size; 	/*Size of buffer used -- for compression */
  FH_COMPRESS_OUT_TYPE 	compress_out_size;	/* -- for compression - output buffer */
  FH_ENCRIPT_IN_TYPE 	encript_in_size;		/* -- for encription - input buff */
  FH_ENCRIPT_OUT_TYPE 	encript_out_size;		/* -- for encription - output buff */
};


#if 0

struct upd_stat
{
    mode_t mode;
};

typedef struct upd_stat upd_stat_t;


/* dir_header is structure that describes a directory. */
/* It describes permission for every directory nt the path. */
struct dir_header
{
    CHAR name[FH_PATH_SIZE];
    upd_stat_t stat[FH_DEPTH];
};
#endif

/*	used when read spec file. */
struct file_list {
  struct file_list * next;
  CHAR 				* file_name;
  CHAR 				* path_to_install;
  ULONG  			flags;
  CHAR				compressor[FL_COMPRESSOR_SIZE];
  CHAR				encriptor [FL_ENCRIPTOR_SIZE];
  CHAR				macro_name[FL_MACRO_NAME_SIZE]; /* For parsing */
};

typedef struct file_list file_list_t;

/*	used when read spec file. */
struct group_of_files
{
	struct group_of_files * next;
	char name[GROUP_MAX_LEN];
	file_list_t * files;
};

typedef struct group_of_files group_of_files_t;

#if 0
/**/
struct section_header
{
    UINT buffer_in_size;
    UINT buffer_out_size;
};
#endif

struct cpu_info {
	struct cpu_info * next; 	/* pinter to next cpu info */
	CHAR * 	name;				/* cpu name */
	ULONG 	id;					/* cpu ID   */
	/* TODO */
};

typedef struct cpu_info cpu_info_t;

struct net {
	struct   net * next;	/* next card */
	CHAR mac    [MACSIZE];			/* MAC address of the card  */
	CHAR ip     [IPSIZE];			/* IP address of the card   */
    CHAR router [IPSIZE];
	/* TODO */
};

typedef struct net net_t;

/**/
struct machine_info {
	struct cpu_info * cpu;		/* CPU(s) information */
	INT memory;					/* memory (in Kbytes) */
	
};

typedef struct machine_info machine_info_t;

/* Variables of all kinds that received from OS and environment and configuration file(s) */
struct environment {
	INT					argn;
	CHAR 				** args;
    CHAR                * root; /* It is a root of installation. If user doesn't set root it is PWD */
	CHAR				output_file_name[ENV_NAME_SIZE];
	CHAR				packet_name[PACKET_NAME_SIZE];
	CHAR				packet_description[PACKET_DESCRIPTION_SIZE];
	CHAR				packager[PACKET_PACKAGER_SIZE];
	PACKET_MAJOR_TYPE	major;
	PACKET_MINOR_TYPE	minor;
	PACKET_FLAGS_TYPE	package_flags;
};

typedef struct environment environment_t;


/* Frame it is an piece of data that read from a file into buffer, processed and write to the output */
/* When I write this buffer out I need to describe properties of encryptor and compressor: */
/* which size of the buffer was before and after compression and encryption. */
/* So I reserve at begin of every buffer the room for this structure. */
/* The structure is filled by updater itself, not in a hook! */

struct frame_attr {
    UINT    enc_in;     /* Size of encrypted IN */
    UINT    enc_out;    /* Size of encrypted OUT */
    UINT    comp_in;   
    UINT    comp_out;
};

typedef struct frame_attr frame_attr_t;


/* Input and output buffers */
struct bufs_io
{
	VOID * buffer_in;       /* Input buffer. It means: a data to procedd placed here */
	VOID * buffer_out;      /* Output buffer. It means: the processed data to be placed here */
	ULONG * size_in;         /* The size of data (in chars) placed in the input buffer */
	ULONG * size_out;        /* The size of output buffer. It means size (in chars) of data placed in ouput dir. */

    frame_attr_t frameatr;

    UINT    size_effective;
};

typedef struct bufs_io bufs_io_t;

#if defined(USE_HOOKS)
enum enum_hook_t
{
    e_hook_begin = 0,
    e_hook_spec_read,
    e_hook_in_file_opened,
    e_hook_buffer_in,
    e_hook_encode,
    e_hook_compress,
    e_hook_buffer_out,
    e_hook_decompress,
    e_hook_decode,
    e_hook_checksum,
    e_hook_end
};


typedef INT(*uhook_t)(VOID*, INT);

/* This structure defines thae hooks */
struct updaterhooks 
{
	uhook_t hook_begin;			    /* be called at begin */
    uhook_t hook_spec_read;		    /* be called when speac reading and parsing is done */
    uhook_t hook_in_file_opened;	/* be called when input file opened */	
    uhook_t hook_out_file_opened;	/* be called when output file opened */
    uhook_t hook_buffer_in;			/* be called after buffer read from input file */
	uhook_t hook_encode;			/* get buffer and encode it */
    uhook_t hook_compress;			/* get buffer and compress it */
    uhook_t hook_buffer_out;    	/* be called after buffer wrote to output file */
	uhook_t hook_decompress;		/* get buffer and uncompress it */
	uhook_t hook_decode;			/* get buffer to decode one */
	uhook_t hook_checksum;			/* if exists must return checksum of file_out */
	uhook_t hook_end;				/* be called at the end of updater's work */
	
};

typedef struct updaterhooks uhooks_t;

#endif /* USE_HOOKS */


/*** tags and sets ***/

#define TAG_CHUNK_SIZE 64
#define SET_CHUNK_SIZE 512


struct tag_entry
{
    UINT    tag;                /* Tag number*/
    OFF_T   offset;             /* Offset in archive */
    OFF_T   file;               /* Associated file in archive */
};

typedef struct tag_entry tag_t;


struct tag_chunk
{
    tag_t tags[TAG_CHUNK_SIZE]; /* Array of tags */
    OFF_T next_offset;          /* Pointer to a next chunk in the archive */
    struct tag_chunk * next;    /* Pointer to next chunk in memory */
};

typedef struct tag_chunk tag_chank_t;


struct tag_holder
{
    tag_chank_t *t;
    struct tag_holder * next;
};

typedef struct tag_holder tag_holder_t;


struct set_chunk
{
    UINT    set;                    /* Set number */
    UINT    tags[SET_CHUNK_SIZE];   /* tags of the set */
    OFF_T   next;                   /* Offset of the next chunk */
};

typedef struct set_chunk set_chunk_t;

struct set_holder
{
    set_chunk_t * s;
    struct set_holder_t * next;
};

typedef struct set_holder set_holder_t;



/* Main structure of updater. Must argument of every function */
struct updater_core {
	environment_t	env;                        /* Misc. info as: output file name, etc. */
	FD_T			* file_out;					/* Output file */
	FD_T 			* file_in;                  /* Current input file - changes through running */
	bufs_io_t		buffers;                    /* Buffers used for input, output, compression and encoding. */
#if 0
	cpu_info_t 		cpu_info;                   /* CPU information */
	net_t 			net;                        /* Network information */
	machine_info_t 	machine_info;               /* Misc. info about machine where updater runs */
#endif
	file_list_t 	* file_list;                /* A list of files to pack.*/
    tag_holder_t    * tabs;
    set_holder_t    * sets;

#if defined(USE_HOOKS)
    INT             e_stage;                    /* Which stage the updater is? Used in hooks. */
	uhooks_t		hooks;                      /* Hooks: pointers to funcions, each of these run chain of hooks. */
#endif /* USE_HOOKS */

};

typedef struct updater_core ucore_t;
typedef struct packet_header packet_header_t ;
typedef struct file_header file_header_t ;


/* Macros for "easy live" */
#define UPD_FOUT(s)     (s->file_out)
#define UPD_FIN(s)      (s->file_in)
#define UPD_BUFFOUT(s)    (s->buffers.buffer_out)
#define UPD_BUFFIN(s)    (s->buffers.buffer_in)
#define UPD_BUFFOUT(s)    (s->buffers.buffer_out)
#define UPD_BUFFOUT_SIZE(s)    (s->buffers.size_out)
#define UPD_BUFFIN_SIZE(s)    (s->buffers.size_in)


#endif /* 	__UPDATER_H__ */

